﻿using LightCAD.MathLib;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Security.Permissions;
using System.Threading;

namespace LightCAD.Three
{

    public sealed class BufferAttributeContext
    {
        public readonly Vector3 _vector = new Vector3();
        public readonly Vector2 _vector2 = new Vector2();
    }
    public sealed class BufferGeometryContext
    {
        //public int _id = 0;
        public readonly Matrix4 _m1 = new Matrix4();
        public readonly Object3D _obj = new Object3D();
        public readonly Vector3 _offset = new Vector3();
        public readonly Box3 _box = new Box3();
        public readonly Box3 _boxMorphTargets = new Box3();
        public readonly Vector3 _vector = new Vector3();
    }
    public sealed class InterleavedBufferAttributeContext
    {
        public readonly Vector3 _vector = new Vector3();
    }
    public sealed class CameraHelperContext
    {
        public readonly Vector3 _vector = new Vector3();
        public readonly Camera _camera = new Camera();
    }
    public sealed class HemisphereLightHelperContext
    {
        public readonly Vector3 _vector = new Vector3();
        public readonly Color _color1 = new Color();
        public readonly Color _color2 = new Color();
    }
    public sealed class SkeletonHelperContext
    {
        public readonly Vector3 _vector = new Vector3();
        public readonly Matrix4 _boneMatrix = new Matrix4();
        public readonly Matrix4 _matrixWorldInv = new Matrix4();
    }
    public sealed class SpotLightHelperContext
    {
        public readonly Vector3 _vector = new Vector3();
    }
   
 
    
    public sealed class SkinnedMeshContext
    {
        public readonly Vector3 _basePosition = new Vector3();
        public readonly Vector4 _skinIndex = new Vector4();
        public readonly Vector4 _skinWeight = new Vector4();
        public readonly Vector3 _vector3 = new Vector3();
        public readonly Matrix4 _matrix4 = new Matrix4();
        public readonly Vector3 _vertex = new Vector3();
    }
    public sealed class CCDIKSolverContext
    {
        public readonly Quaternion _q = new Quaternion();
        public readonly Vector3 _targetPos = new Vector3();
        public readonly Vector3 _targetVec = new Vector3();
        public readonly Vector3 _effectorPos = new Vector3();
        public readonly Vector3 _effectorVec = new Vector3();
        public readonly Vector3 _linkPos = new Vector3();
        public readonly Quaternion _invLinkQ = new Quaternion();
        public readonly Vector3 _linkScale = new Vector3();
        public readonly Vector3 _axis = new Vector3();
        public readonly Vector3 _vector = new Vector3();
        public readonly Matrix4 _matrix = new Matrix4();
    }

    public sealed class LineSegmentsGeometryContext
    {
        public readonly Box3 _box = new Box3();
        public readonly Vector3 _vector = new Vector3();
    }
    public sealed class AnimationMixerContext
    {
        public readonly double[] _controlInterpolantsResultBuffer = new double[1];
    }
    public sealed class StereoCameraContext
    {
        public readonly Matrix4 _eyeRight = new Matrix4();
        public readonly Matrix4 _eyeLeft = new Matrix4();
        public readonly Matrix4 _projectionMatrix = new Matrix4();
    }

    public sealed class Object3DContext
    {
        //public int _object3DId = 0;
        public readonly Vector3 _v1 = new Vector3();
        public readonly Quaternion _q1 = new Quaternion();
        public readonly Matrix4 _m1 = new Matrix4();
        public readonly Vector3 _target = new Vector3();
        public readonly Vector3 _position = new Vector3();
        public readonly Vector3 _scale = new Vector3();
        public readonly Quaternion _quaternion = new Quaternion();
    }
    public sealed class EdgesGeometryContext
    {
        public readonly Vector3 _v0 = new Vector3();
        public readonly Vector3 _v1 = new Vector3();
        public readonly Vector3 _normal = new Vector3();
        public readonly Triangle _triangle = new Triangle();
    }
    public sealed class ArrowHelperContext
    {
        public readonly Vector3 _axis = new Vector3();
    }
    public sealed class BoxHelperContext
    {
        public readonly Box3 _box = new Box3();
    }
    public sealed class DirectionalLightHelperContext
    {
        public readonly Vector3 _v1 = new Vector3();
        public readonly Vector3 _v2 = new Vector3();
        public readonly Vector3 _v3 = new Vector3();
    }

    public sealed class LightShadowContext
    {
        public readonly Matrix4 _projScreenMatrix = new Matrix4();
        public readonly Vector3 _lightPositionWorld = new Vector3();
        public readonly Vector3 _lookTarget = new Vector3();
    }
    public sealed class PointLightShadowContext
    {
        public readonly Matrix4 _projScreenMatrix = new Matrix4();
        public readonly Vector3 _lightPositionWorld = new Vector3();
        public readonly Vector3 _lookTarget = new Vector3();
    }
  
    
   
    public sealed class InstancedMeshContext
    {
        public readonly Matrix4 _instanceLocalMatrix = new Matrix4();
        public readonly Matrix4 _instanceWorldMatrix = new Matrix4();
        public readonly ListEx<Raycaster.Intersection> _instanceIntersects = new ListEx<Raycaster.Intersection>();
        public readonly Mesh _mesh = new Mesh();
        public readonly Box3 _box3 = /*@__PURE__*/ new Box3();
        public readonly Sphere _sphere = /*@__PURE__*/ new Sphere();
    }
    public sealed class LineContext
    {
        public readonly Vector3 _start = new Vector3();
        public readonly Vector3 _end = new Vector3();
        public readonly Matrix4 _inverseMatrix = new Matrix4();
        public readonly Ray _ray = new Ray();
        public readonly Sphere _sphere = new Sphere();
    }
    public sealed class LineSegmentsContext
    {
        public readonly Vector3 _start = new Vector3();
        public readonly Vector3 _end = new Vector3();
    }
    public sealed class LODContext
    {
        public readonly Vector3 _v1 = new Vector3();
        public readonly Vector3 _v2 = new Vector3();
    }
    public sealed class MeshContext
    {
        public readonly Matrix4 _inverseMatrix = new Matrix4();
        public readonly Ray _ray = new Ray();
        public readonly Sphere _sphere = new Sphere();
        public readonly Vector3 _sphereHitAt = new Vector3();
        public readonly Vector3 _vA = new Vector3();
        public readonly Vector3 _vB = new Vector3();
        public readonly Vector3 _vC = new Vector3();
        public readonly Vector3 _tempA = new Vector3();
        public readonly Vector3 _morphA = new Vector3();
        public readonly Vector2 _uvA = new Vector2();
        public readonly Vector2 _uvB = new Vector2();
        public readonly Vector2 _uvC = new Vector2();
        public readonly Vector3 _normalA = new Vector3();
        public readonly Vector3 _normalB = new Vector3();
        public readonly Vector3 _normalC = new Vector3();
        public readonly Vector3 _intersectionPoint = new Vector3();
        public readonly Vector3 _intersectionPointWorld = new Vector3();
    }
    public sealed class PointsContext
    {
        public readonly Matrix4 _inverseMatrix = new Matrix4();
        public readonly Ray _ray = new Ray();
        public readonly Sphere _sphere = new Sphere();
        public readonly Vector3 _position = new Vector3();
    }
    public sealed class SkeletonContext
    {
        public readonly Matrix4 _offsetMatrix = new Matrix4();
    }
    public sealed class SpriteContext
    {
        public readonly BufferGeometry _geometry;
        public readonly Vector3 _intersectPoint = new Vector3();
        public readonly Vector3 _worldScale = new Vector3();
        public readonly Vector3 _mvPosition = new Vector3();
        public readonly Vector2 _alignedPosition = new Vector2();
        public readonly Vector2 _rotatedPosition = new Vector2();
        public readonly Matrix4 _viewWorldMatrix = new Matrix4();
        public readonly Vector3 _vA = new Vector3();
        public readonly Vector3 _vB = new Vector3();
        public readonly Vector3 _vC = new Vector3();
        public readonly Vector2 _uvA = new Vector2();
        public readonly Vector2 _uvB = new Vector2();
        public readonly Vector2 _uvC = new Vector2();
    }
    public sealed class LineSegments2Context
    {
        public readonly Vector3 _start = new Vector3();
        public readonly Vector3 _end = new Vector3();
        public readonly Vector4 _start4 = new Vector4();
        public readonly Vector4 _end4 = new Vector4();
        public readonly Vector4 _ssOrigin = new Vector4();
        public readonly Vector3 _ssOrigin3 = new Vector3();
        public readonly Matrix4 _mvMatrix = new Matrix4();
        public readonly Line3 _line = new Line3();
        public readonly Vector3 _closestPoint = new Vector3();
        public readonly Box3 _box = new Box3();
        public readonly Sphere _sphere = new Sphere();
        public readonly Vector4 _clipToWorldVector = new Vector4();
        public Ray _ray;
        public double _lineWidth;
    }
    public sealed class WebGLShaderStageContext
    {
        public int _id = 0;
    }

    public sealed class ThreeThreadContext
    {
        public readonly int id;
        internal static readonly ConcurrentDictionary<int, ThreeThreadContext> Contexts = new ConcurrentDictionary<int, ThreeThreadContext>();
        public readonly BufferAttributeContext BufferAttrCtx = new BufferAttributeContext();
        public readonly BufferGeometryContext BufferGeoCtx = new BufferGeometryContext();
        public readonly InterleavedBufferAttributeContext InterleavedBufferAttributeCtx = new InterleavedBufferAttributeContext();
        public readonly CameraHelperContext CameraHelperCtx = new CameraHelperContext();
        public readonly HemisphereLightHelperContext HemisphereLightHelperCtx = new HemisphereLightHelperContext();
        public readonly SkeletonHelperContext SkeletonHelperCtx = new SkeletonHelperContext();
        public readonly SpotLightHelperContext SpotLightHelperCtx = new SpotLightHelperContext();
        public readonly SkinnedMeshContext SkinnedMeshCtx = new SkinnedMeshContext();
        public readonly CCDIKSolverContext CCDIKSolverCtx = new CCDIKSolverContext();
        public readonly LineSegmentsGeometryContext LineSegmentsGeometryCtx = new LineSegmentsGeometryContext();
        public readonly AnimationMixerContext AnimationMixerCtx = new AnimationMixerContext();
        public readonly StereoCameraContext StereoCameraCtx = new StereoCameraContext();
        public readonly Object3DContext Object3DCtx = new Object3DContext();
        public readonly EdgesGeometryContext EdgesGeometryCtx = new EdgesGeometryContext();
        public readonly ArrowHelperContext ArrowHelperCtx = new ArrowHelperContext();
        public readonly BoxHelperContext BoxHelperCtx = new BoxHelperContext();
        public readonly DirectionalLightHelperContext DirectionalLightHelperCtx = new DirectionalLightHelperContext();
        public readonly LightShadowContext LightShadowCtx = new LightShadowContext();
        public readonly PointLightShadowContext PointLightShadowCtx = new PointLightShadowContext();
        public readonly InstancedMeshContext InstancedMeshCtx = new InstancedMeshContext();
        public readonly LineContext LineCtx = new LineContext();
        public readonly LineSegmentsContext LineSegmentsCtx = new LineSegmentsContext();
        public readonly LODContext LODCtx = new LODContext();
        public readonly MeshContext MeshCtx = new MeshContext();
        public readonly PointsContext PointsCtx = new PointsContext();
        public readonly SkeletonContext SkeletonCtx = new SkeletonContext();
        public readonly SpriteContext SpriteCtx = new SpriteContext();
        public readonly LineSegments2Context LineSegments2Ctx = new LineSegments2Context();

        private ThreeThreadContext()
        {
            this.id = Thread.CurrentThread.ManagedThreadId;
        }

        public static ThreeThreadContext GetCurrThreadContext()
        {
            var tctx = ThreeThreadContext.Contexts.GetOrAdd(Thread.CurrentThread.ManagedThreadId, (id) => new ThreeThreadContext());
            return tctx;
        }
        public static int NewId(ConcurrentDictionary<int, int> objIndex)
        {
            var threadId = Thread.CurrentThread.ManagedThreadId;
            return objIndex.AddOrUpdate(threadId, Add, Update);
        }
        private static int Add(int threadId)
        {
            return threadId * (int)(1e+7);
        }
        private static int Update(int threadId, int currId)
        {
            return currId + 1;
        }
    }
}
